package symmetric;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;

public class RSAcrypt {

	/**
	 * @param args
	 */
	String tmp = "Hello";

	public static void main(String[] args) {
		// TODO Auto-generated method stub

		RSAEncodecrypt rs = new RSAEncodecrypt();
		try {
			Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
			// CachedRowSet cacheRS = new CachedRowSetImpl();
			//
			// //
			// cacheRS.setUrl("jdbc:sqlserver://localhost:1433;databaseName=test;user=sa;password=sa");
			//
			// // hoac set user, pass ro rang hon
			// cacheRS.setUrl("jdbc:sqlserver://BDK-PC;databaseName=Demo;");
			// cacheRS.setUsername("sa");
			// cacheRS.setPassword("123456");
			// // sql
			// cacheRS.setCommand("SELECT * FROM SINHVIEN");
			//
			// // execute
			// cacheRS.setType(java.sql.ResultSet.TYPE_SCROLL_INSENSITIVE);
			//
			// cacheRS.setTransactionIsolation(java.sql.Connection.TRANSACTION_READ_UNCOMMITTED);
			// cacheRS.setConcurrency(java.sql.ResultSet.CONCUR_UPDATABLE);
			// cacheRS.execute();
			//
			// while (cacheRS.next()) {
			// // System.out.println(rs.DecryptRSA(cacheRS.get("TenSV")));
			// }

			Connection connection = DriverManager
					.getConnection("jdbc:sqlserver://BDK-PC;databaseName=demo;user=sa;password=123456");
			String sql = "{ call dbo.sp_insertSV(?,?,?) }";
			CallableStatement state = connection.prepareCall(sql);
			// truyen tham so xu ly
			String tensv = "khi�m";
			String enTenSV = rs.EncryptRSA(tensv);
			state.setString(0, enTenSV);

			state.setBinaryStream(1,
					new ByteArrayInputStream(rs.publicK.getEncoded()));
			state.setBinaryStream(2,
					new ByteArrayInputStream(rs.privateK.getEncoded()));

			// ------------------------
			System.out.println(state.execute());

		} catch (SQLException e) {
			e.printStackTrace();
		} catch (ClassNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	}
}

class RSAEncodecrypt {
	PublicKey publicK;
	PrivateKey privateK;

	private KeyPairGenerator gen;

	private KeyPair key;
	private byte[] encryptedOutput;
	private byte[] DecryptedOutput;

	public RSAEncodecrypt() {
		// TODO Auto-generated constructor stub
		try {

			gen = KeyPairGenerator.getInstance("RSA");
			gen.initialize(512, new SecureRandom());
			key = gen.generateKeyPair();
			publicK = key.getPublic();
			privateK = key.getPrivate();

		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void dumpKeyPair(KeyPair keyPair) {
		PublicKey pub = keyPair.getPublic();
		System.out.println("Public Key: " + getHexString(pub.getEncoded()));

		PrivateKey priv = keyPair.getPrivate();
		System.out.println("Private Key: " + getHexString(priv.getEncoded()));
	}

	public String getHexString(byte[] b) {
		String result = "";
		for (int i = 0; i < b.length; i++) {
			result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
		}
		return result;
	}

	public void SaveKeyPair(String path, KeyPair keyPair) throws IOException {
		PrivateKey privateKey = keyPair.getPrivate();
		PublicKey publicKey = keyPair.getPublic();

		// Store Public Key.
		X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(
				publicKey.getEncoded());
		FileOutputStream fos = new FileOutputStream(path + "/public.key");
		fos.write(x509EncodedKeySpec.getEncoded());
		fos.close();

		// Store Private Key.
		PKCS8EncodedKeySpec pkcs8EncodedKeySpec = new PKCS8EncodedKeySpec(
				privateKey.getEncoded());
		fos = new FileOutputStream(path + "/private.key");
		fos.write(pkcs8EncodedKeySpec.getEncoded());
		fos.close();
	}

	public KeyPair LoadKeyPair(String path, String algorithm)
			throws IOException, NoSuchAlgorithmException,
			InvalidKeySpecException {
		// Read Public Key.
		File filePublicKey = new File(path + "/public.key");
		FileInputStream fis = new FileInputStream(path + "/public.key");
		byte[] encodedPublicKey = new byte[(int) filePublicKey.length()];
		fis.read(encodedPublicKey);
		fis.close();

		// Read Private Key.
		File filePrivateKey = new File(path + "/private.key");
		fis = new FileInputStream(path + "/private.key");
		byte[] encodedPrivateKey = new byte[(int) filePrivateKey.length()];
		fis.read(encodedPrivateKey);
		fis.close();

		// Generate KeyPair.
		KeyFactory keyFactory = KeyFactory.getInstance(algorithm);
		X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(
				encodedPublicKey);
		PublicKey publicKey = keyFactory.generatePublic(publicKeySpec);

		PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(
				encodedPrivateKey);
		PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

		return new KeyPair(publicKey, privateKey);
	}

	public String EncryptRSA(String str1) {
		Cipher cipher;
		try {
			cipher = Cipher.getInstance("RSA");
			// cipher.init(Cipher.ENCRYPT_MODE, publicK);
			cipher.init(Cipher.ENCRYPT_MODE, publicK);
			encryptedOutput = cipher.doFinal(str1.getBytes("UTF-8"));
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return getHexString(encryptedOutput);

	}

	public String DecryptRSA(byte[] str1) {
		Cipher cipher;
		try {
			cipher = Cipher.getInstance("RSA");
			// cipher.init(Cipher.DECRYPT_MODE, privateK);
			cipher.init(Cipher.DECRYPT_MODE, privateK);
			encryptedOutput = str1;
			DecryptedOutput = cipher.doFinal(encryptedOutput);
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (BadPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return getHexString(DecryptedOutput);
	}

}
